/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package session.stateless.MRP.ATPCheck;

import entity.CRM.LineItem;
import entity.CRM.SaleOrder;
import entity.CRM.SaleQuotation;
import entity.MRP.ProductionPlan.PlannedDailyDemand;
import entity.MRP.ProductionPlan.PlannedMonthlyDemand;
import entity.MRP.ProductionPlan.PlannedWeeklyDemand;
import entity.Product;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;
import javaclass.ProductType;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import session.stateless.CRM.SaleOrderBeanLocal;
import session.stateless.MRP.ProductionPlan.MonthlyProductionPlanBeanLocal;
import session.stateless.ProductBeanLocal;

/**
 *
 * @author Vincent
 */
@Stateless
public class ATPCheckSessionBean implements ATPCheckSessionBeanLocal {

    // Add business logic below. (Right-click in editor and choose
    // "Insert Code > Add Business Method")
    @PersistenceContext (unitName = "M10-IS3102-ejbPU")
    private EntityManager entityManager; 
    @EJB
    SaleOrderBeanLocal saleOrderBeanLocal;
    @EJB
    MonthlyProductionPlanBeanLocal monthlyProductionPlanBeanLocal;
    @EJB
    ProductBeanLocal productBeanLocal;
    
    
    public void ATPCheckSessionBean(){}
    @Override
    public Long getLeadTimeSQ(Long saleQuotationId){
        
        //get the sale quotation from db based on the id
        SaleQuotation sq = entityManager.find(SaleQuotation.class, saleQuotationId);
        
        //check whether inventory have enough, if enough then return lead time = 0;
        long leadTime = 0;
        boolean enoughInventory = true;
        //lists to store products and quantities that required to produce
        List<Product> listOfProducts = new ArrayList<Product>();
        List<Long> listOfQuantities = new ArrayList<Long>();
        for (LineItem li:sq.getLineItems()){
            Product p = entityManager.find(Product.class, li.getProductPrice().getProductType());
            if (p.getProductBalance().getBalance() < li.getLineItemQuantity()){
                enoughInventory = false;
                listOfProducts.add(p);
                listOfQuantities.add(listOfProducts.indexOf(p), li.getLineItemQuantity());
            }
        }
        if (enoughInventory){
            return leadTime;
        }
        
        //if not, check whether production plan for current month can fulfill order or not
        //available amt for each product
        //                   = amt in inventory + amt from current date to end date of month 
        //                   - aggregate amt from sale order
        boolean enoughProduction = true;
        //lists to store products and quantities that required to update production plan
        List<Product> listOfProductsToUpdate = new ArrayList<Product>();
        List<Long> listOfQuantitiesToUpdate = new ArrayList<Long>();
        for(int index = 0; index <= (listOfProducts.size()-1); index++){
            Long availableAmount = this.getAvailableAmount(listOfProducts.get(index));
            if (listOfQuantities.get(index) > availableAmount){
                enoughProduction = false;
                listOfProductsToUpdate.add(listOfProducts.get(index));
                listOfQuantitiesToUpdate.add(listOfQuantities.get(index) - availableAmount);
            }
        }
        if (enoughProduction){
            //calculate lead time
            leadTime = calculateLeadTime(listOfProducts, listOfQuantities);
            return leadTime;
        }
        
        //if not, try to increase utilization of current month production plan
        leadTime = calculateLeadTimeWithUpdateUtilization(listOfProductsToUpdate, listOfQuantitiesToUpdate);
        if (leadTime != -1){
            System.out.println("if update utiliza this month"+leadTime);
            return leadTime;
        }
        
        //if not, check lead time in the future (only consider next month)
        //check whether there is enough production plan for next month
        //lists to store products and quantities that required to update production plan
        listOfProductsToUpdate = new ArrayList<Product>();
        listOfQuantitiesToUpdate = new ArrayList<Long>();
        enoughProduction = true;
        for(int index = 0; index <= (listOfProducts.size()-1); index++){
            Long availableAmount = this.getAvailableAmountNextMonth(listOfProducts.get(index));
            if (listOfQuantities.get(index) > availableAmount){
                enoughProduction = false;
                listOfProductsToUpdate.add(listOfProducts.get(index));
                listOfQuantitiesToUpdate.add(listOfQuantities.get(index) - availableAmount);
            }
        }
        if (enoughProduction){
            //calculate lead time
            leadTime = calculateLeadTimeNextMonth(listOfProducts, listOfQuantities);
            return leadTime;
        }
        
        //if not, try to increase utilization of current month and next month production plan
        leadTime = calculateLeadTimeWithUpdateUtilizationNextMonth(listOfProducts, listOfQuantities);
        if (leadTime != -1){
            return leadTime;
        }
        
        //return -1 if can not find solution
        return leadTime;
    }
    
    @Override
    public Long getLeadTimeSO(Long saleOrderId){
        
        //get the sale quotation from db based on the id
        SaleOrder so = entityManager.find(SaleOrder.class, saleOrderId);
        //check whether inventory have enough, if enough then return lead time = 0;
        long leadTime = 0;
        boolean enoughInventory = true;
        //lists to store products and quantities that required to produce
        List<Product> listOfProducts = new ArrayList<Product>();
        List<Long> listOfQuantities = new ArrayList<Long>();
        for (LineItem li:so.getLineItems()){
            Product p = entityManager.find(Product.class, li.getProductPrice().getProductType());
            if (p.getProductBalance().getBalance() < li.getLineItemQuantity()){
                enoughInventory = false;
                listOfProducts.add(p);
                listOfQuantities.add(listOfProducts.indexOf(p), li.getLineItemQuantity());
            }
        }
        if (enoughInventory){
            System.out.println("if enough inventory"+leadTime);
            return leadTime;
        }
        
        //if not, check whether production plan for current month can fulfill order or not
        //available amt for each product
        //                   = amt in inventory + amt from current date to end date of month 
        //                   - aggregate amt from sale order
        boolean enoughProduction = true;
        //lists to store products and quantities that required to update production plan
        List<Product> listOfProductsToUpdate = new ArrayList<Product>();
        List<Long> listOfQuantitiesToUpdate = new ArrayList<Long>();
        for(int index = 0; index <= (listOfProducts.size()-1); index++){
            Long availableAmount = this.getAvailableAmount(listOfProducts.get(index));
            if (listOfQuantities.get(index) > availableAmount){
                enoughProduction = false;
                listOfProductsToUpdate.add(listOfProducts.get(index));
                listOfQuantitiesToUpdate.add(listOfQuantities.get(index) - availableAmount);
            }
        }
        if (enoughProduction){
            //calculate lead time
            leadTime = calculateLeadTime(listOfProducts, listOfQuantities);
            System.out.println("if enought production"+leadTime);
            return leadTime;
        }
        
        //if not, try to increase utilization of current month production plan
        leadTime = calculateLeadTimeWithUpdateUtilization(listOfProducts, listOfQuantities);
        if (leadTime != -1){
            System.out.println("calculateLeadTime with updateUtilization"+leadTime);
            return leadTime;
        }
        
        //if not, check lead time in the future (only consider next month)
        //check whether there is enough production plan for next month
        //lists to store products and quantities that required to update production plan
        listOfProductsToUpdate = new ArrayList<Product>();
        listOfQuantitiesToUpdate = new ArrayList<Long>();
        enoughProduction = true;
        for(int index = 0; index <= (listOfProducts.size()-1); index++){
            Long availableAmount = this.getAvailableAmountNextMonth(listOfProducts.get(index));
            if (listOfQuantities.get(index) > availableAmount){
                enoughProduction = false;
                listOfProductsToUpdate.add(listOfProducts.get(index));
                listOfQuantitiesToUpdate.add(listOfQuantities.get(index) - availableAmount);
            }
        }
        if (enoughProduction){
            //calculate lead time
            leadTime = calculateLeadTimeNextMonth(listOfProducts, listOfQuantities);
            System.out.println("if enoughProduction calculateLTnext month"+leadTime);
            return leadTime;
        }
        
        //if not, try to increase utilization of current month and next month production plan
        leadTime = calculateLeadTimeWithUpdateUtilizationNextMonth(listOfProducts, listOfQuantities);
        if (leadTime != -1){
            System.out.println("calculateLeadTimeWithUpdateUtilizationNextMonth"+leadTime);
            return leadTime;
        }
        
        //return -1 if can not find solution
        return leadTime;
    }
    
    //available amt for each product
    //               = amt in inventory + amt from current date to end date of current month 
    //               - aggregate amt from sale order
    private Long getAvailableAmount(Product p){
        String productName = "";
        if (p.getProductType() == ProductType.NUTS){
            productName = "A";
        }
        if (p.getProductType() == ProductType.FRUITS){
            productName = "B";
        }
        if (p.getProductType() == ProductType.CHOCOLATE_NUTS){
            productName = "C";
        }
        if (p.getProductType() == ProductType.REDCURRANT_FRUITS){
            productName = "D";
        }
                    
        //calculate amtInventory
        Long amtInventory = p.getProductBalance().getBalance();
        
        //calculate amtProduction
        Long amtProduction = (long)0;
        int currentDate = Calendar.getInstance().get(Calendar.DATE);
        int currentMonth = Calendar.getInstance().get(Calendar.MONTH) + 1;
        int currentYear = Calendar.getInstance().get(Calendar.YEAR);
        String monthStr = currentMonth + "/" + currentYear;
        
        PlannedMonthlyDemand mPP = monthlyProductionPlanBeanLocal.findByMonth(monthStr);        
        //get list of planned working days
        List<PlannedDailyDemand> pDDList = new ArrayList<PlannedDailyDemand>();
        System.out.println(mPP.getListOfPlannedWeeklyDemand().size());
        
        for (PlannedWeeklyDemand pWD:mPP.getListOfPlannedWeeklyDemand()){
            for(PlannedDailyDemand pDD:pWD.getPlannedDailyDemand()){
                int day = Integer.parseInt(pDD.getDayName().split("/")[0]);
                if (day > currentDate){
                    
                    pDDList.add(pDD);
                }
            }
        }
        
        System.out.println("pDDList"+pDDList.size());
        //check whether there are still days left to get production of current month
        if (pDDList.size()>0){     
            for (int index = 0; index <= pDDList.size() - 1; index++){
                    amtProduction += pDDList.get(index).getDailyDemand(productName);
            }
        }
        
        //calculate amtSaleOrder
        Long amtSaleOrder = (long)0;
        for (SaleOrder so:saleOrderBeanLocal.getSaleOrders_ConfirmedOnly()){
            for (LineItem li:so.getLineItems()){
                if (p.getProductType() == li.getProductPrice().getProductType()){
                    amtSaleOrder += li.getQuantityLeft();
                }
            }
        }
        System.out.println("given product"+p.getDescription()+"amtInven    "+amtInventory+"amtPro  "+amtProduction+"   "+amtSaleOrder);
        return amtInventory + amtProduction - amtSaleOrder;
    }
    
    //get the maximum lead time for current month
    private Long calculateLeadTime(List<Product> listOfProducts, List<Long> listOfQuantities){
        long maxLeadTime = 0;
        
        for (int index = 0; index <= listOfProducts.size() - 1; index++){
            Product p = listOfProducts.get(index);
            long leadTime = 0;
            String productName = "";
            if (p.getProductType() == ProductType.NUTS){
                productName = "A";
            }
            if (p.getProductType() == ProductType.FRUITS){
                productName = "B";
            }
            if (p.getProductType() == ProductType.CHOCOLATE_NUTS){
                productName = "C";
            }
            if (p.getProductType() == ProductType.REDCURRANT_FRUITS){
                productName = "D";
            }
            
            //calculate amtInventory
            Long amtInventory = p.getProductBalance().getBalance();
            
            //calculate amtSaleOrder
            Long amtSaleOrder = (long)0;
            for (SaleOrder so:saleOrderBeanLocal.getSaleOrders_ConfirmedOnly()){
                for (LineItem li:so.getLineItems()){
                    if (p.getProductType() == li.getProductPrice().getProductType()){
                        amtSaleOrder += li.getQuantityLeft();
                    }
                }
            }

            //calculate amtProduction
            Long amtProduction = (long)0;
            int currentDate = Calendar.getInstance().get(Calendar.DATE);
            int currentMonth = Calendar.getInstance().get(Calendar.MONTH) + 1;
            int currentYear = Calendar.getInstance().get(Calendar.YEAR);
            String monthStr = currentMonth + "/" + currentYear;
            PlannedMonthlyDemand mPP = monthlyProductionPlanBeanLocal.findByMonth(monthStr);        
            //get list of planned working days
            List<PlannedDailyDemand> pDDList = new ArrayList<PlannedDailyDemand>();
            for (PlannedWeeklyDemand pWD:mPP.getListOfPlannedWeeklyDemand()){
                for(PlannedDailyDemand pDD:pWD.getPlannedDailyDemand()){
                    int day = Integer.parseInt(pDD.getDayName().split("/")[0]);
                    if (day > currentDate){
                        pDDList.add(pDD);
                    }
                }
            }
                 
            for (int i = 0; i <= pDDList.size() - 2; i++){
                amtProduction += pDDList.get(i).getDailyDemand(productName);
                if (amtInventory + amtProduction - amtSaleOrder >= listOfQuantities.get(index)){
                    leadTime += 1;
                    break;
                }
                else {
                    leadTime += 1;
                }
            }
            
            if (maxLeadTime < leadTime){
                maxLeadTime = leadTime;
            }
 
        }
        return maxLeadTime;
    }
    
    //method to check utilization of given list of products and list of quantities
    private Long calculateLeadTimeWithUpdateUtilization(List<Product> listOfProducts, List<Long> listOfQuantities){
        long leadTime = -1;
        
        //get number of days left
        int daysLeft = 0;
        int currentDate = Calendar.getInstance().get(Calendar.DATE);
        int currentMonth = Calendar.getInstance().get(Calendar.MONTH) + 1;
        int currentYear = Calendar.getInstance().get(Calendar.YEAR);
        int currentWeek = Calendar.getInstance().get(Calendar.WEEK_OF_MONTH);
        String monthStr = currentMonth + "/" + currentYear;
        PlannedMonthlyDemand mPP = monthlyProductionPlanBeanLocal.findByMonth(monthStr);        
        
        //get lead time for material requirements
        int materialLeadTime = 0;
        for (Product p:listOfProducts){
            if (p.getProductType() == ProductType.FRUITS || p.getProductType() == ProductType.REDCURRANT_FRUITS){
                //if it is Fruits or Redcurrant Fruits then lead time is 3 weeks
                materialLeadTime = 3;
                break;
            }
        }
        
        //if there is no Fruits or Redcurrant Fruits then lead time is 2 weeks
        if (materialLeadTime == 0){
            materialLeadTime = 2;
        }
        
        System.out.println("material LEad TIme"+materialLeadTime);
        //only update production plan if current week + material lead time is not last week of month
        if (currentWeek + materialLeadTime < mPP.getListOfPlannedWeeklyDemand().size()){
            //get list of planned working days excluding current week and week in material lead time
            List<PlannedDailyDemand> pDDList = new ArrayList<PlannedDailyDemand>();
            for (int i = 0; i <= mPP.getListOfPlannedWeeklyDemand().size() - 1; i++){
                PlannedWeeklyDemand pWD = mPP.getListOfPlannedWeeklyDemand().get(i);
                int weekOfMonth = Integer.parseInt( pWD.getWeekNumber().toString());
                //only add planned working day for weeks after current week + material lead time
                if (currentWeek + materialLeadTime < weekOfMonth){
                    for(PlannedDailyDemand pDD:pWD.getPlannedDailyDemand()){
                        pDDList.add(pDD);
                    }
                }
            }

            long amtCatOne = 0;
            long amtCatTwo = 0;
            for (int i = 0; i <= pDDList.size() - 1; i++){
                daysLeft += 1;
                
            }

            for (int i = 0; i <= listOfProducts.size() - 1; i++){
                if (listOfProducts.get(i).getProductType() == ProductType.NUTS || listOfProducts.get(i).getProductType() == ProductType.FRUITS){
                    amtCatOne += listOfQuantities.get(i);
                }
                else{
                    amtCatTwo += listOfQuantities.get(i);
                }
            }
            
            //calculate amtSaleOrder
            Long amtSaleOrder = (long)0;
            for (SaleOrder so:saleOrderBeanLocal.getSaleOrders_ConfirmedOnly()){
                for (LineItem li:so.getLineItems()){
                    if (li.getProductPrice().getProductType() == ProductType.NUTS || li.getProductPrice().getProductType() == ProductType.FRUITS){
                        amtCatOne += li.getLineItemQuantity();
                    }
                    else{
                        amtCatTwo += li.getLineItemQuantity();
                    }
                }
            }
            for (Product p:productBeanLocal.getProductList()){
                if (p.getProductType() == ProductType.NUTS || p.getProductType() == ProductType.FRUITS){
                    amtCatOne -= p.getProductBalance().getBalance();
                }
                else{
                    amtCatTwo -= p.getProductBalance().getBalance();
                }
            }
            //full capacity in hours of remaining days excluding current week
            long capacity = 24 * daysLeft;

            
            long actualCapacity = Math.round(Math.ceil(amtCatOne/50 + (double)amtCatTwo/45));

            if (!monthlyProductionPlanBeanLocal.checkUtilization(actualCapacity, capacity)){
                return leadTime;
            }
            
            leadTime = Math.round(Math.ceil((double)actualCapacity/24)) + materialLeadTime * 5;
            
        }
        
        return leadTime;
    }
    
    //available amt for each product
    //               = amt in inventory + amt from current date to end date of current month 
    //               + amt from next month - aggregate amt from sale order
    private Long getAvailableAmountNextMonth(Product p){
        String productName = "";
        if (p.getProductType() == ProductType.NUTS){
            productName = "A";
        }
        if (p.getProductType() == ProductType.FRUITS){
            productName = "B";
        }
        if (p.getProductType() == ProductType.CHOCOLATE_NUTS){
            productName = "C";
        }
        if (p.getProductType() == ProductType.REDCURRANT_FRUITS){
            productName = "D";
        }
        
        //VARIABLE 1
        //calculate amtInventory
        Long amtInventory = p.getProductBalance().getBalance();
        
        //VARIABLE 2 + 3
        //calculate amtProduction
        Long amtProduction = (long)0;
        int currentDate = Calendar.getInstance().get(Calendar.DATE);
        int currentMonth = Calendar.getInstance().get(Calendar.MONTH) + 1;
        int currentYear = Calendar.getInstance().get(Calendar.YEAR);
        String monthStr = currentMonth + "/" + currentYear;
        PlannedMonthlyDemand mPP = monthlyProductionPlanBeanLocal.findByMonth(monthStr);        
        //get list of planned working days
        List<PlannedDailyDemand> pDDList = new ArrayList<PlannedDailyDemand>();
        for (PlannedWeeklyDemand pWD:mPP.getListOfPlannedWeeklyDemand()){
            for(PlannedDailyDemand pDD:pWD.getPlannedDailyDemand()){
                int day = Integer.parseInt(pDD.getDayName().split("/")[0]);
                if (day > currentDate){
                    pDDList.add(pDD);
                }
            }
        }
        //check whether there are still days left to get production for current month
        if (pDDList.size() > 0){     
            for (int index = 0; index <= pDDList.size() - 1; index++){
                amtProduction += pDDList.get(index).getDailyDemand(productName);
            }
        }
        
        int nextMonth = Calendar.getInstance().get(Calendar.MONTH) + 2;
        int yearOfNextMonth = Calendar.getInstance().get(Calendar.YEAR);
        if (nextMonth == 13) {
            nextMonth = 1;
            yearOfNextMonth += 1;
        }
        
        monthStr = nextMonth + "/" + yearOfNextMonth;
        mPP = monthlyProductionPlanBeanLocal.findByMonth(monthStr);        
        //get list of planned working days
        pDDList = new ArrayList<PlannedDailyDemand>();
        for (PlannedWeeklyDemand pWD:mPP.getListOfPlannedWeeklyDemand()){
            for(PlannedDailyDemand pDD:pWD.getPlannedDailyDemand()){
                pDDList.add(pDD);
            }
        }
          
        for (int index = 0; index <= pDDList.size() - 1; index++){
            amtProduction += pDDList.get(index).getDailyDemand(productName);
        }
        
        //VARIABLE 4
        //calculate amtSaleOrder
        Long amtSaleOrder = (long)0;
        for (SaleOrder so:saleOrderBeanLocal.getSaleOrders_ConfirmedOnly()){
            for (LineItem li:so.getLineItems()){
                if (p.getProductType() == li.getProductPrice().getProductType()){
                    amtSaleOrder += li.getQuantityLeft();
                }
            }
        }
        
        return amtInventory + amtProduction - amtSaleOrder;
    }    
    
    //get the maximum lead time for current month
    private Long calculateLeadTimeNextMonth(List<Product> listOfProducts, List<Long> listOfQuantities){
        long maxLeadTime = 0;
        
        for (int index = 0; index <= listOfProducts.size() - 1; index++){
            Product p = listOfProducts.get(index);
            long leadTime = 0;
            String productName = "";
            if (p.getProductType() == ProductType.NUTS){
                productName = "A";
            }
            if (p.getProductType() == ProductType.FRUITS){
                productName = "B";
            }
            if (p.getProductType() == ProductType.CHOCOLATE_NUTS){
                productName = "C";
            }
            if (p.getProductType() == ProductType.REDCURRANT_FRUITS){
                productName = "D";
            }
            
            //calculate amtInventory
            Long amtInventory = p.getProductBalance().getBalance();
            
            //calculate amtSaleOrder
            Long amtSaleOrder = (long)0;
            for (SaleOrder so:saleOrderBeanLocal.getSaleOrders_ConfirmedOnly()){
                for (LineItem li:so.getLineItems()){
                    if (p.getProductType() == li.getProductPrice().getProductType()){
                        amtSaleOrder += li.getLineItemQuantity();
                    }
                }
            }

            //VARIABLE 2 + 3
            //calculate amtProduction
            Long amtProduction = (long)0;
            int currentDate = Calendar.getInstance().get(Calendar.DATE);
            int currentMonth = Calendar.getInstance().get(Calendar.MONTH) + 1;
            int currentYear = Calendar.getInstance().get(Calendar.YEAR);
            String monthStr = currentMonth + "/" + currentYear;
            PlannedMonthlyDemand mPP = monthlyProductionPlanBeanLocal.findByMonth(monthStr);        
            //get list of planned working days
            List<PlannedDailyDemand> pDDList = new ArrayList<PlannedDailyDemand>();
            for (PlannedWeeklyDemand pWD:mPP.getListOfPlannedWeeklyDemand()){
                for(PlannedDailyDemand pDD:pWD.getPlannedDailyDemand()){
                    pDDList.add(pDD);
                }
            }
             
            for (int i = 0; i <= pDDList.size() - 2; i++){
                int day = Integer.parseInt(pDDList.get(i).getDayName().split("/")[0]);
                if (day > currentDate){
                    leadTime += 1;
                    amtProduction += pDDList.get(i).getDailyDemand(productName);
                }
            }
        
            int nextMonth = Calendar.getInstance().get(Calendar.MONTH) + 2;
            int nextYear = Calendar.getInstance().get(Calendar.YEAR);
            if (nextMonth == 13) {
                nextMonth = 1;
                nextYear += 1;
            }

            monthStr = nextMonth + "/" + nextYear;
            mPP = monthlyProductionPlanBeanLocal.findByMonth(monthStr);        
            //get list of planned working days
            pDDList = new ArrayList<PlannedDailyDemand>();
            for (PlannedWeeklyDemand pWD:mPP.getListOfPlannedWeeklyDemand()){
                for(PlannedDailyDemand pDD:pWD.getPlannedDailyDemand()){
                    pDDList.add(pDD);
                }
            }

            for (int i = 0; i <= pDDList.size() - 1; i++){
                amtProduction += pDDList.get(i).getDailyDemand(productName);
                if (amtInventory + amtProduction - amtSaleOrder >= listOfQuantities.get(index)){
                    leadTime += 1;
                    break;
                }
                else {
                    leadTime += 1;
                }
            }
            
            if (maxLeadTime < leadTime){
                maxLeadTime = leadTime;
            }
 
        }
        return maxLeadTime;
    }    
    
    //method to check utilization for current month and next month of given list of products and list of quantities
    private Long calculateLeadTimeWithUpdateUtilizationNextMonth(List<Product> listOfProducts, List<Long> listOfQuantities){
        long leadTime = -1;
        
        //get number of days left
        int daysLeft = 0;
        int currentDate = Calendar.getInstance().get(Calendar.DATE);
        int currentMonth = Calendar.getInstance().get(Calendar.MONTH) + 1;
        int currentYear = Calendar.getInstance().get(Calendar.YEAR);
        int currentWeek = Calendar.getInstance().get(Calendar.WEEK_OF_MONTH);
        int currentWeekOfYear = Calendar.getInstance().get(Calendar.WEEK_OF_YEAR);
        String monthStr = currentMonth + "/" + currentYear;
        PlannedMonthlyDemand mPP = monthlyProductionPlanBeanLocal.findByMonth(monthStr);   
        
        
        //get lead time for material requirements
        int materialLeadTime = 0;
        for (Product p:listOfProducts){
            if (p.getProductType() == ProductType.FRUITS || p.getProductType() == ProductType.REDCURRANT_FRUITS){
                //if it is Fruits or Redcurrant Fruits then lead time is 3 weeks
                materialLeadTime = 3;
                break;
            }
        }
        
        //if there is no Fruits or Redcurrant Fruits then lead time is 2 weeks
        if (materialLeadTime == 0){
            materialLeadTime = 2;
        }
        
        //get list of planned working days excluding current week and week in material lead time
        List<PlannedDailyDemand> pDDList = new ArrayList<PlannedDailyDemand>();
        for (int i = 0; i <= mPP.getListOfPlannedWeeklyDemand().size() - 1; i++){
            PlannedWeeklyDemand pWD = mPP.getListOfPlannedWeeklyDemand().get(i);
            int weekOfMonth = Integer.parseInt( pWD.getWeekNumber().toString());
            //only add planned working day for weeks after current week + material lead time
            if (currentWeek + materialLeadTime < weekOfMonth){
                for(PlannedDailyDemand pDD:pWD.getPlannedDailyDemand()){
                    pDDList.add(pDD);
                }
            }
        }

        long amtCatOne = 0;
        long amtCatTwo = 0;
        for (int i = 0; i <= pDDList.size() - 2; i++){
            int day = Integer.parseInt(pDDList.get(i).getDayName().split("/")[0]);
            if (day > currentDate){
                daysLeft += 1;
            }
        }
        
        int nextMonth = Calendar.getInstance().get(Calendar.MONTH) + 2;
        int yearOfNextMonth = Calendar.getInstance().get(Calendar.YEAR);
        Calendar calendar = new GregorianCalendar();
        if (nextMonth == 13) {
            nextMonth = 1;
            yearOfNextMonth += 1;
        }

        monthStr = nextMonth + "/" + yearOfNextMonth;
        mPP = monthlyProductionPlanBeanLocal.findByMonth(monthStr);        
        //get list of planned working days for next month
        pDDList = new ArrayList<PlannedDailyDemand>();
        for (PlannedWeeklyDemand pWD:mPP.getListOfPlannedWeeklyDemand()){
            for(PlannedDailyDemand pDD:pWD.getPlannedDailyDemand()){
                int day = Integer.parseInt(pDD.getDayName().split("/")[0]);
                calendar.set(yearOfNextMonth, nextMonth - 1, day);
                //only add the working day of next month if the week is after taking account of material lead time
                if (currentWeekOfYear + materialLeadTime < calendar.get(Calendar.WEEK_OF_YEAR)){
                    pDDList.add(pDD);
                }
            }
        }
        
        for (int i = 0; i <= pDDList.size() - 1; i++){
            daysLeft += 1;
        }
            
        for (int i = 0; i <= listOfProducts.size() - 1; i++){
            if (listOfProducts.get(i).getProductType() == ProductType.NUTS || listOfProducts.get(i).getProductType() == ProductType.FRUITS){
                amtCatOne += listOfQuantities.get(i);
            }
            else{
                amtCatTwo += listOfQuantities.get(i);
            }
        }
        //calculate amtSaleOrder
        Long amtSaleOrder = (long)0;
        for (SaleOrder so:saleOrderBeanLocal.getSaleOrders_ConfirmedOnly()){
            for (LineItem li:so.getLineItems()){
                if (li.getProductPrice().getProductType() == ProductType.NUTS || li.getProductPrice().getProductType() == ProductType.FRUITS){
                    amtCatOne += li.getLineItemQuantity();
                }
                else{
                    amtCatTwo += li.getLineItemQuantity();
                }
            }
        }
        for (Product p:productBeanLocal.getProductList()){
            if (p.getProductType() == ProductType.NUTS || p.getProductType() == ProductType.FRUITS){
                amtCatOne -= p.getProductBalance().getBalance();
            }
            else{
                amtCatTwo -= p.getProductBalance().getBalance();
            }
        }
        System.out.println("days lEft"+daysLeft+ "  "+amtCatOne+"   "+amtCatTwo);
        //full capacity in hours of remaining days
        long capacity = 24 * daysLeft;
        long actualCapacity = Math.round(Math.ceil(amtCatOne/50 + (double)amtCatTwo/45));
            
        if (!monthlyProductionPlanBeanLocal.checkUtilization(actualCapacity, capacity)){
            return leadTime;
        }
        leadTime = Math.round(Math.ceil((double)actualCapacity/24)) + materialLeadTime * 5;
        return leadTime;
    }    
}